**Title: Frames and Text Effects

We have only worked within the context of the current document, until now. It is also
possible to affect the contents of other documents, such as frames or even windows. The
document object by default refers to the current document, whether that is a complete
page or an individual frame. The top, parent, frame and window objects let us refer to
documents displayed elsewhere in the browser. Rather confusingly, the window object
refers to the location of the script calling it, which may be a frame rather than a
window. The less confusing alternative is to use self, which refers to the same thing.
Each window has a frames[] array, containing the sub-frames of the current document.
window.frames.length contains the number of frames and window.frames[0] refers to the
first frame. Frames can also be referred to by name, if we have a document containing
two frames, called "menu" and "main". We can refer to the menu frame with any of

window.frames[0]
self.frames[0]
frames[0]
window.menu
self.menu
menu

So to get the title of the main frame, we would use main.document.title. Using names
rather than array numbers is easier to read and make rearranging the page layout easier
too. There are times you would wish to use numbers, such as when working with all
frames in a document. This example will force a refresh of all frames

function RefreshFrames()
{
for (i = 0; i < frames.length; i++) frames[i].location.reload(true);
}

Yes, we sneaked in something new there. The location object represents and controls the
URL of the window (or frame). You can read the URL with location.href and reload it with
location(reload). Adding "true" to the reload call forces a reload even if the version
on the server is the same.

**xhead: Moving up the frame hierarchy

You may have noticed a flaw in the idea of including this function in the document that
defines the frames. Since a frameset contains only frame definitions and no other
content, how do we call it? We could call it as an onLoad event, to force a refresh each
time the frameset is loaded, or we could call it from within one of the other frames. We
could do this with a button or event in the main frame that calls parent.RefreshFrames(). The
parent object refers to the window that contains the current window object, for a frame
this is the frameset. Just as you can nest framesets, you can nest parent calls,
parent.parent refers to the next level up. This can get pretty messy, if you want to
refer to the top level document, the one representing the physical browser window, use
top. If the current document is the top level window, top and parent simply refer to the
window itself. You can use this to test whether you are in a frame or not with "if (top
== self)". Here's an example that provides a link to escape when the current document is
in a frame:

<script type="text/javascript" language="JavaScript">
<!--
if (top != self)
{
document.write('<div align="center">Stuck in a frame? ');
document.write('<a href="JavaScript:void top.location.replace(location.href);">');
document.writeln('Click here to escape</a>');
}
// ->
</script>

There's three new things on one line here. The "JavaScript:" part of the URL tells the
browser to execute the URL as a script rather than trying to load anything from the
server. It's a quick and easy way of running short scripts or calling functions. The
"void" operator ensures that the JavaScript returns no result. Otherwise, if the
function returned a value the browser would display it. The function itself uses
location twice, the second call uses location.href to get the URL of the current
document. This is passed to the first call that uses it to replace the current top level
document with location.replace().

You could add this to the bottom of any page that may be linked from outside your site,
avoiding problems with framed sites that neglect to add 'target="_top"' to the link. We
could take this a stage further and automate the process by setting the onLoad handler
of the page to

onLoad="if (top != self) top.location.replace(location.href);return true;"

Another way of handling multiple documents is to use more than one browser window. Most
people find this sort of approach awkward to use, and not all browsers support multiple
windows. If you must use this approach, you open a new window with the open() method

NewWindow = open(URL,name,features)

Where "features" defines which of the standard browser features the window will possess.
You can then refer to the contents of this window with NewWindow.document. One
disadvantage of this approach is that there is no way to refer to any window that wasn't
opened by your script, including the one running the script. It's probably best to
avoid getting involved in this.





**xhead: Text effects

JavaScript can be used to insert random text or scroll messages. Here's an example:

function RandomQuote()
{
Quotes = new Array(
"RAM disk is not an installation procedure.",
"Press any key... no, no, no, NOT THAT ONE!",
"Excuse me for butting in, but I'm interrupt-driven."
);

document.write(Quotes[Math.floor(Math.random() * Quotes.length)]);
}

The function first builds an array containing the various quotes. Notice that the last
one does not have a comma. The syntax for creating an array with pre-defined elements
is

ArrayName = new Array(Element1,Element2,...,LastElement)

The elements can be any type of data. Here we have three elements, numbered 0 to 2.
Math.random returns a number between 0 and 1. Multiplying this by
the number of elements in the array gives a number between 0 and 3. Math.floor
returns the integer part of this, 0, 1 or 2 in this case. We then use that as the array
index. It's important that we use Math.floor to get the integer part of the random
number. Math.round will round the number up as well as down, a random number greater
than 2.5 would be rounded up to 3, which would produce an error as Quotes[3] is not
defined. Adding extra quotes is simply a matter of adding more lines to the array
definition. The quote is inserted in the HTML by adding a call to the function at the
appropriate place.

A variation on this theme is to insert different text each day.

function TipOfTheDay()
{
Tips = new Array(
"define array as before"
);

Today = new Date();
document.write(Tips[Today.getDate() % Tips.length]);
}

This is similar to the random quote function, except we use the date to pick the array
element. To do this, we create a new object of type Date, called Today. We can then
apply any of the methods available to the Date object. The getDate() method returns the
date of the month, you could also use getDay() to return the day of the week ads a
number between 0 (Sunday) and 6 (Saturday). The % operator performs a modulo division.
It ensures that the number used to index the array always refers to and existing
element.




**xhead: Scrolling messages

These examples show how you can display different text each time a page is loaded, but
once the page is loaded the text stays the same. What about providing continually
changing text n the browser page? This is not possible within the context of the main
HTML text, at least not with the current Amiga browsers. There are two places where we
can change text after the page has loaded. One is the status bar, which we used
previously to display messages with onMouseOver. The other is in a form text gadget.
Scrolling text relies on the onTimeout() method. This accepts two arguments, the second
is a a delay in milliseconds. The first is a command to execute after the delay.
onTimeout() exits after executing the command, so it is common for a function to call
itself via another onTimeout before it exits. First we create a text box for the
function to use:

<form name="ScrollForm">
<input size="50" Name="ScrollBar">
</form>

The names and size are important, if you change them, change the function to match. We start
the scrolling with the onLoad handler for the page:

<body onLoad="setTimeout('ScrollText()',10);return true;">

Here is the main function that should be put in the <HEAD> section of the page:

<script type="text/javascript" language="JavaScript">
<!-- //
// Change these variables to suit
Size = 50; // This must be the same as the SIZE attribute in the INPUT definition
Delay = 100;
Message = "This is an example of a ticker-tape banner. The text scrolls from right to left, clearing between each message.";

// Initialise
Spaces = "";
for (i = 0; i < Size; i++) Spaces += ' ';
Message = Spaces + Message + Spaces;
Pos = 0;

function ScrollText()
{
document.ScrollForm.ScrollBar.value = Message.substring(Pos, Pos + Size);
Pos += 1;
Pos = Pos % (Message.length - Size)
setTimeout('ScrollText();',Delay);
}

// -->
</script>

The first part is executed only once, setting the variables containing the message text
and other items needed by the function. A variable defined outside of a function is
actually a property of the window object, Message is really window.Message.
Variables defined within a function are local to that call to the function. Inside a
function, when JavaScript interpreter is given the variable xyz it will first look for a
local variable of that name and then for window.xyz.

We pad each end of Message with enough spaces to fill the box, so that the box starts
empty and clears after each pass of the message. The function is executed repeatedly,
with only a 1/10th second pause between, so it's important to reduce the amount of work
done here and keep it as short as possible. The substring method takes two arguments, a
start and end position. String.substring(x,y) returns the string starting at character x
and ending at y-1. This may seem odd but it has two advantages. It's safe to give
string.length as the second argument, even though the last character is string.length-1.
Secondly, y-x is the length of the substring.

The next line increments the Pos variable, so that the message is displayed one place to
the left next time. Then we make sure that Pos doesn't get too large before calling the
function again via setTimeout().

The script can be modified to display the message in the browser's status bar instead.
Replace the first line of the function with

window.status = Message.substring(Pos, Message.length);

and increase the Size variable to a suitable value. That can be a bit tricky as you
don't know how wide the user's status bar is, either in pixels or characters.